Digital logic circuits must sometimes coordinate operations across a synchronization boundary between two different clock domains operating at different clock speeds. In particular, a first-in-first-out (FIFO) memory is sometimes used to transfer data, commands and/or other information between the two different clock domains. Data is stored into the FIFO memory in a "write" clock domain at a write clock speed and read from the FIFO memory in a "read" clock domain at a read clock speed.
A FIFO memory write pointer, typically a register, is maintained in the write clock domain to point to the FIFO memory location in which data can be stored into the FIFO memory. A FIFO memory read pointer, also typically a register, is maintained in the read clock domain to point to the FIFO memory location from which data can be read from the FIFO memory. The FIFO memory read pointer and the FIFO memory write pointer are compared to each other to generate status information for the FIFO memory. Typically, the status information includes an "empty" signal which indicates that all FIFO memory locations are empty, or do not contain valid data. A "full" signal indicates that all FIFO memory locations are full, or contain valid data. The empty signal is used to determine whether data can currently be read from the FIFO memory. The full signal is used to determine whether data can currently be added to the FIFO memory.
Using the full and empty signals, a synchronization mechanism is implemented in the FIFO memory to prevent "overrun" and "underrun" conditions when writing to and reading from the FIFO memory. An overrun condition occurs when data is added to a FIFO memory location and overwrites previous data that has not yet been read from that FIFO memory location. An underrun condition occurs when data is read from a FIFO memory location before valid data has been stored into that FIFO memory location. The FIFO memory operations are typically synchronized by passing "handshaking" signals between the write clock domain and the read clock domain to request, acknowledge and reject data operations on the FIFO memory.
When there is data to be added to the FIFO memory, a "write request" handshaking signal is initiated in the write clock domain as a request directed to the read clock domain for permission to write data into the FIFO memory. The write request handshaking signal includes the value of the write pointer from the write clock domain and the data to be stored into the FIFO memory. A "return" handshaking signal from the read clock domain is either an "acknowledgment" or a "rejection" depending upon the status of the FIFO memory at the time of the write request. To determine the status of the FIFO memory, the value of the write pointer in the handshaking signal received in the read clock domain is compared to the value of the read pointer in the read clock domain to determine whether the FIFO memory is full. If the FIFO memory is full, the return handshaking signal is a rejection. If the FIFO memory is not full, the data is stored into the FIFO memory and the return handshaking signal is an acknowledgment.
Before data is read from the FIFO memory, a "read request" handshaking signal is initiated by the read clock domain as a request directed to the write clock domain for permission to read data from the FIFO memory. The read request handshaking signal includes the value of the read pointer from the read clock domain. A return handshaking signal from the write clock domain forms an acknowledgment or rejection depending upon the status of the FIFO memory at the time of the read request. To determine the status of the FIFO memory, the value of the read pointer in the handshaking signal received in the write clock domain is compared to the value of the write pointer in the write clock domain to determine whether the FIFO memory is empty. If the FIFO memory is empty, the return handshaking signal is a rejection. If the FIFO memory is not empty, data is read from the FIFO memory and included in the return handshaking signal, which is an acknowledgment.
The handshaking signals pass through a series of synchronizer flip-flops which are clocked by the clock domain that receives the handshaking signal. The round-trip handshake may take several clock cycles to complete depending on the number of synchronizer flip-flops in each clock domain. Accordingly, a read or write of the FIFO memory cannot be done on every clock cycle in the respective clock domain because it takes several cycles for the handshake to complete.
A FIFO memory can be implemented which allows data operations to occur in two different clock domains without handshaking signals. The contents of the FIFO memory read pointer and the FIFO memory write pointer are made available in both clock domains to generate the full signal in the write clock domain and the empty signal in the read clock domain. The full signal is typically set when the value in the FIFO memory read pointer is greater than the FIFO memory write pointer by a quantity of one. In other words, the full signal is set when incrementing the value in the FIFO memory write pointer would result in a quantity that is the same as the value in the FIFO memory read pointer. The empty signal is set when the FIFO memory read pointer and the FIFO memory write pointer contain the same FIFO memory location value. The contents of the FIFO memory read pointer must be synchronized to the clock domain in which data is stored to the FIFO memory and the contents of the FIFO memory write pointer must be synchronized to the clock domain in which data is read from the FIFO memory. If either pointer is not properly synchronized to the other respective clock domain, an indeterminate value may be clocked into the clock domain while the value in the pointer transitions from one value to another. As a result, the full or empty signals derived from the value clocked into the clock domain may be invalid.
The FIFO memory location values in the FIFO pointers are typically encoded using "gray code" to facilitate synchronization between the clock domains. Gray code involves encoding binary values in a manner in which only one bit in the binary value changes as the gray code value is incremented or decremented. Thus, if the gray code value is clocked into one of the clock domains while the gray code value is being incremented or decremented, only one binary bit may have an indeterminate value, which can generally be easily accounted for. Typically, one or more flip-flop registers are used to synchronize the gray code value in the clock domain and to resolve the value of the changing bit. The synchronized gray code value formed in the clock domain will be either the previous gray code value or the new incremented, or decremented, gray code value. In either case, the gray code value is valid and synchronized in the clock domain.
Synchronizing the FIFO memory between two clock domains by using handshaking signals does not allow data to be added to the FIFO memory during each write clock cycle or read from the FIFO memory during each read clock cycle. Encoding FIFO memory location values using gray code requires an even number of FIFO memory locations to ensure that only one bit in the binary representation of the location value changes when the location value is incremented or decremented. If a FIFO memory with an odd number of locations is desired, the FIFO memory may contain an extra location that is unneeded. The extra location will consume area on an integrated circuit and may decrease performance of the FIFO memory by increasing interconnect length, capacitive loading, or other characteristics of the integrated circuit.
It is with respect to these and other background considerations that the present invention has evolved.